#ifndef TANSDEAL_CPP_456_432_987_564_308_756_034
#define TANSDEAL_CPP_456_432_987_564_308_756_034

#include "TansDeal.h"

UDP_PDU::UDP_PDU(UDP_HPP& udp_hpp)
{   Magic = *reinterpret_cast<uint16_t*>(udp_hpp.Data);
    Type = *reinterpret_cast<uint8_t*>(udp_hpp.Data + 2);
    GroupID = *reinterpret_cast<uint8_t*>(udp_hpp.Data + 3);
    ACK = GroupID & 1u;
    TSC = (GroupID >> 1) & 1u;
    GroupID >>=2;
    SourceUsreID = *reinterpret_cast<uint32_t*>(udp_hpp.Data + 4);
    SerialCode = *reinterpret_cast<uint32_t*>(udp_hpp.Data + 8);
    CRC16 = *reinterpret_cast<uint16_t*>(udp_hpp.Data + 12);
    UsrDataLength = *reinterpret_cast<uint16_t*>(udp_hpp.Data + 14);
    UsrData = (uint8_t*)mi_malloc(UsrDataLength);
    memcpy(UsrData, udp_hpp.Data + 16, UsrDataLength);
}
UDP_PDU::UDP_PDU():
    Magic(0),
    Type(0),
    GroupID(0), ACK(0), TSC(0),
    SourceUsreID(0),
    SerialCode(0),
    CRC16(0),
    UsrDataLength(0),
    UsrData(nullptr)
{}
UDP_PDU::UDP_PDU(const UDP_PDU& _UDP_PDU_):
    Magic(_UDP_PDU_.Magic),
    Type(_UDP_PDU_.Type),
    GroupID(_UDP_PDU_.GroupID), ACK(_UDP_PDU_.ACK), TSC(_UDP_PDU_.TSC),
    SourceUsreID(_UDP_PDU_.SourceUsreID),
    SerialCode(_UDP_PDU_.SerialCode),
    CRC16(_UDP_PDU_.CRC16),
    UsrDataLength(_UDP_PDU_.UsrDataLength),
    UsrData(_UDP_PDU_.UsrData)
{}
UDP_PDU::~UDP_PDU()
{
    mi_free(UsrData);
}
UDP_HPP UDP_PDU::Build()
{   uint8_t* data = (uint8_t*)mi_malloc(16+UsrDataLength);
    *reinterpret_cast<uint16_t*>(data) = Magic;
    *reinterpret_cast<uint8_t*>(data + 2) = Type;
    *reinterpret_cast<uint8_t*>(data + 3) = (GroupID << 2)^(ACK << 1)^TSC;
    *reinterpret_cast<uint32_t*>(data + 4) = SourceUsreID;
    *reinterpret_cast<uint32_t*>(data + 8) = SerialCode;
    *reinterpret_cast<uint16_t*>(data + 12) = CRC16;
    *reinterpret_cast<uint16_t*>(data + 14) = UsrDataLength;
    memcpy(data + 16, UsrData, UsrDataLength);
    UDP_HPP udp_hpp(data, 16 + UsrDataLength);
    return udp_hpp;
}
void UDP_PDU::operator=(UDP_PDU& udp_hpp)
{   Magic = udp_hpp.Magic;
    Type = udp_hpp.Type;
    GroupID = udp_hpp.GroupID;
    ACK = udp_hpp.ACK;
    TSC = udp_hpp.TSC;
    SourceUsreID = udp_hpp.SourceUsreID;
    SerialCode = udp_hpp.SerialCode;
    CRC16 = udp_hpp.CRC16;
    UsrDataLength = udp_hpp.UsrDataLength;
    mi_free(UsrData);
    UsrData = (uint8_t*)mi_malloc(UsrDataLength);
    memcpy(UsrData, udp_hpp.UsrData, UsrDataLength);
}
bool UDP_PDU::operator==(UDP_PDU& udp_hpp)
{   return (Magic == udp_hpp.Magic) &&
           (Type == udp_hpp.Type) &&
           (GroupID == udp_hpp.GroupID) &&
           (ACK == udp_hpp.ACK) &&
           (TSC == udp_hpp.TSC) &&
           (SourceUsreID == udp_hpp.SourceUsreID) &&
           (SerialCode == udp_hpp.SerialCode) &&
           (CRC16 == udp_hpp.CRC16) &&
           (UsrDataLength == udp_hpp.UsrDataLength);
}
bool UDP_PDU::operator!=(UDP_PDU& udp_hpp)
{   return (Magic == udp_hpp.Magic) ||
           (Type == udp_hpp.Type) ||
           (GroupID == udp_hpp.GroupID) ||
           (ACK == udp_hpp.ACK) ||
           (TSC == udp_hpp.TSC) ||
           (SourceUsreID == udp_hpp.SourceUsreID) ||
           (SerialCode == udp_hpp.SerialCode) ||
           (CRC16 == udp_hpp.CRC16) ||
           (UsrDataLength == udp_hpp.UsrDataLength);
}

UDP_HPP::UDP_HPP(UDP_PDU& udp_pdu)
{   Data = (uint8_t*)mi_malloc(udp_pdu.UsrDataLength + 16);
    *reinterpret_cast<uint16_t*>(Data) = udp_pdu.Magic;
    *reinterpret_cast<uint8_t*>(Data + 2) = udp_pdu.Type;
    *reinterpret_cast<uint8_t*>(Data + 3) = (udp_pdu.GroupID << 2)^(udp_pdu.ACK << 1)^udp_pdu.TSC;
    *reinterpret_cast<uint32_t*>(Data + 4) = udp_pdu.SourceUsreID;
    *reinterpret_cast<uint32_t*>(Data + 8) = udp_pdu.SerialCode;
    *reinterpret_cast<uint16_t*>(Data + 12) = udp_pdu.CRC16;
    *reinterpret_cast<uint16_t*>(Data + 14) = udp_pdu.UsrDataLength;
    memcpy(Data + 16, udp_pdu.UsrData, udp_pdu.UsrDataLength);
}
UDP_HPP::UDP_HPP(uint8_t* data, size_t length):
    Data(data),
    Length(length)
{}
UDP_HPP::UDP_HPP():
    Data(nullptr),
    Length(0)
{}
UDP_HPP::UDP_HPP(const UDP_HPP& udp_hpp)
{   Length = udp_hpp.Length;
    Data = (uint8_t*)mi_malloc(Length);
    memcpy(Data, udp_hpp.Data, Length);
}
UDP_HPP::~UDP_HPP()
{
    if(Data) mi_free(Data);
}
UDP_PDU UDP_HPP::Analysis()
{   UDP_PDU udp_pdu;
    udp_pdu.Magic = *reinterpret_cast<uint16_t*>(Data);
    udp_pdu.Type = *reinterpret_cast<uint8_t*>(Data + 2);
    udp_pdu.GroupID = *reinterpret_cast<uint8_t*>(Data + 3);
    udp_pdu.ACK = udp_pdu.GroupID & 1u;
    udp_pdu.TSC = (udp_pdu.GroupID >> 1) & 1u;
    udp_pdu.GroupID >>=2;
    udp_pdu.SourceUsreID = *reinterpret_cast<uint32_t*>(Data + 4);
    udp_pdu.SerialCode = *reinterpret_cast<uint32_t*>(Data + 8);
    udp_pdu.CRC16 = *reinterpret_cast<uint16_t*>(Data + 12);
    udp_pdu.UsrDataLength = *reinterpret_cast<uint16_t*>(Data + 14);
    udp_pdu.UsrData = (uint8_t*)mi_malloc(udp_pdu.UsrDataLength);
    memcpy(udp_pdu.UsrData, Data + 16, udp_pdu.UsrDataLength);
    return udp_pdu;
}
bool UDP_HPP::LegalVerify()
{   if(*reinterpret_cast<uint16_t*>(Data + 12) == CRC16(Data+16, *reinterpret_cast<uint16_t*>(Data + 14)))
    {
        return true;
    }
    return false;
}
bool UDP_HPP::MagicVerify(uint16_t magic)
{
    return *reinterpret_cast<uint16_t*>(Data) == magic;
}
uint8_t* UDP_HPP::begin()
{
    return Data;
}
uint8_t* UDP_HPP::end()
{
    return Data + Length;
}
size_t UDP_HPP::size()
{
    return Length;
}
void UDP_HPP::operator=(UDP_HPP& udp_hpp)
{   Length = udp_hpp.Length;
    mi_free(Data);
    Data = (uint8_t*)mi_malloc(Length);
    memcpy(Data, udp_hpp.Data, Length);
}
bool UDP_HPP::operator==(UDP_HPP& udp_hpp)
{
    return (Length == udp_hpp.Length);
}
bool UDP_HPP::operator!=(UDP_HPP& udp_hpp)
{
    return (Length != udp_hpp.Length);
}
UDP_HPP UDP_HPP_Build(UDP_PDU& udp_pdu)
{
    return UDP_HPP(udp_pdu);
}
UDP_PDU UDP_PDU_Analysis(UDP_HPP& udp_hpp)
{
    return UDP_PDU(udp_hpp);
}
uint16_t CRC16(uint8_t* data, uint16_t length)
{   uint16_t crc = 0xFFFF;
    for(; length > 1; length-=2)
    {   crc ^= *data++;
        crc ^= *data++ << 8;
    }
    if(length) {
        crc ^= *data;
    }
    return crc;
}

#endif